package services

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"
	httpclient "tp-plugin/http_client"

	mqtt "github.com/eclipse/paho.mqtt.golang"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

var mqttClient mqtt.Client

func StartSub() {
	// 启动mqtt客户端
	subscribeMqttClient()
	// 订阅设备消息
	subscribe()
	// 订阅平台的命令
	subscribeCommand()
}

func subscribeMqttClient() {
	// 初始化配置
	opts := mqtt.NewClientOptions()
	opts.AddBroker(viper.GetString("mqtt.broker"))
	opts.SetUsername(viper.GetString("mqtt.username"))
	opts.SetPassword(viper.GetString("mqtt.password"))
	opts.SetClientID(viper.GetString("mqtt.client_id"))
	// 干净会话
	opts.SetCleanSession(true)
	// 恢复客户端订阅，需要broker支持
	opts.SetResumeSubs(true)
	// 失败重连
	opts.SetAutoReconnect(true)
	opts.SetConnectRetryInterval(5 * time.Second)  // 初始连接重试间隔
	opts.SetMaxReconnectInterval(20 * time.Second) // 丢失连接后的最大重试间隔
	// 消息顺序
	opts.SetOrderMatters(false)
	// 设置连接处理程序
	opts.SetOnConnectHandler(func(c mqtt.Client) {
		logrus.Info("mqtt connect success")
	})

	mqttClient = mqtt.NewClient(opts)
	// 等待连接成功
	for {
		if token := mqttClient.Connect(); token.Wait() && token.Error() != nil {
			logrus.Error("MQTT Broker 1 连接失败:", token.Error())
			time.Sleep(5 * time.Second)
			continue
		}
		break
	}
}

// 订阅设备消息
func subscribe() {
	// 订阅消息
	if token := mqttClient.Subscribe(viper.GetString("mqtt.topic_to_subscribe_device"), 0, func(client mqtt.Client, msg mqtt.Message) {
		logrus.Debug("接收主题:", msg.Topic())
		logrus.Debug("\ni<==接收消息:", msg.Payload())
		err := DealMessage(msg.Topic(), msg.Payload())
		if err != nil {
			logrus.Warn("处理消息失败:", err)
		}
	}); token.Wait() && token.Error() != nil {
		logrus.Error("订阅消息失败:", token.Error())
		panic(token.Error())
	}
}

// 订阅命令消息
func subscribeCommand() {
	// 订阅消息
	if token := mqttClient.Subscribe(viper.GetString("mqtt.topic_to_subscribe_command"), 0, func(client mqtt.Client, msg mqtt.Message) {
		logrus.Debug("接收主题:", msg.Topic())
		logrus.Debug("\ni<==接收消息:", string(msg.Payload()))
		err := DealTpCommand(msg.Topic(), msg.Payload())
		if err != nil {
			logrus.Warn("处理消息失败:", err)
		}
	}); token.Wait() && token.Error() != nil {
		logrus.Error("订阅消息失败:", token.Error())
		panic(token.Error())
	}
}

// 发布遥测数据
func PublishTelemetry(mac string, payload []byte) error {
	topic := viper.GetString("mqtt.topic_to_publish_telemetry")
	// 组装payload
	newMsgJson, err := AssemblePayload(mac, payload)
	if err != nil {
		logrus.Warn("组装payload失败:", err)
		return err
	}
	if token := mqttClient.Publish(topic, 0, false, newMsgJson); token.Wait() && token.Error() != nil {
		logrus.Warn("发布消息失败:", token.Error())
	}
	logrus.Debug("遥测主题:", topic)
	logrus.Debug("\n==>tp 发送消息成功:", string(payload))
	return nil
}

// 发布设备属性
func PublishAttributes(mac string, payload []byte) error {
	topic := viper.GetString("mqtt.topic_to_publish_attributes") + GetMessageID()
	// 组装payload
	newMsgJson, err := AssemblePayload(mac, payload)
	if err != nil {
		logrus.Warn("组装payload失败:", err)
		return err
	}
	if token := mqttClient.Publish(topic, 0, false, newMsgJson); token.Wait() && token.Error() != nil {
		logrus.Warn("发布消息失败:", token.Error())
	}
	logrus.Debug("属性主题:", topic)
	logrus.Debug("\n==>tp 发送消息成功:", string(payload))
	return nil
}

// 发送数据给设备
func SendDataToDevice(mac string, payload []byte) error {
	topic := mac + viper.GetString("mqtt.topic_to_publish_device")
	if token := mqttClient.Publish(topic, 0, false, payload); token.Wait() && token.Error() != nil {
		logrus.Warn("发送消息失败:", token.Error())
		return token.Error()
	}
	logrus.Debug("设备主题:", topic)
	logrus.Debug("\n==>device 发送消息成功:", payload)
	return nil
}

// 发布事件到平台
func PublishEvent(mac string, payload []byte) error {
	topic := viper.GetString("mqtt.topic_to_publish_event") + GetMessageID()
	// 组装payload
	newMsgJson, err := AssemblePayload(mac, payload)
	if err != nil {
		logrus.Warn("组装payload失败:", err)
		return err
	}
	if token := mqttClient.Publish(topic, 0, false, newMsgJson); token.Wait() && token.Error() != nil {
		logrus.Warn("发布消息失败:", token.Error())
	}
	logrus.Debug("设备主题:", topic)
	logrus.Debug("\n==>tp 发送消息成功:", string(payload))
	return nil
}

func GetMessageID() string {
	// 获取当前Unix时间戳
	timestamp := time.Now().Unix()
	// 将时间戳转换为字符串
	timestampStr := strconv.FormatInt(timestamp, 10)
	// 截取后七位
	messageID := timestampStr[len(timestampStr)-7:]

	return messageID
}

type MqttPayload struct {
	DeviceID string `json:"device_id"`
	Values   []byte `json:"values"`
}

// 组装payload
func AssemblePayload(mac string, payload []byte) ([]byte, error) {
	var mqttPayload MqttPayload
	// 通过mac地址获取设备ID
	deviceID, err := httpclient.DeviceInfo{}.GetDeviceIDByMAC(mac)
	if err != nil {
		return nil, err
	}
	if deviceID == "" {
		return nil, fmt.Errorf("deviceID is empty")
	}
	mqttPayload.DeviceID = deviceID
	mqttPayload.Values = payload
	//logrus.Debug("payload:", string(payload))
	newMsgJson, err := json.Marshal(mqttPayload)
	if err != nil {
		return nil, err
	}
	return newMsgJson, nil
}
